package httpServer

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"gitee.com/windcoder/geekbangCloudNativeWork/go/httpserver/metrics"
	"gitee.com/windcoder/geekbangCloudNativeWork/go/httpserver/utils"
	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"io"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"time"
)

var goUrlCache *utils.GoUrlCache

func init() {
	goUrlCache = new(utils.GoUrlCache)
	goUrlCache.InitCacheDate()
}

func NewServe(url string, port string) *http.Server {
	if port == "" {
		port = "8080"
	}
	// 路由
	mux := http.NewServeMux()
	mux.HandleFunc("/healthz", healthzHandler)
	mux.HandleFunc("/timeOut", timeOutHandler)
	mux.HandleFunc("/go/", goUrlHandler)
	mux.HandleFunc("/api/", apiJsonHandler)
	mux.HandleFunc("/status/500", errHandler)
	mux.Handle("/metrics", promhttp.Handler())
	mux.HandleFunc("/", routeHandler)
	// HTTP 服务配置
	return &http.Server{
		Addr:    url + ":" + port,
		Handler: mux,
	}
}

// 路由配置-通用
// 响应头中返回 request 中的 Header 信息，环境变量中的 VERSION 信息
func routeHandler(reson http.ResponseWriter, r *http.Request) {
	if r.URL.RequestURI() == "/favicon.ico" {
		reson.Header().Set("Content-Type", "image/png")
		base64Str := ""
		// 用于去掉 “data:image/png;base64,” 部分
		i := strings.Index(base64Str, ",")
		dec := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64Str[i+1:]))
		io.Copy(reson, dec)
		return
	}
	// 注册指标统计
	timer := metrics.NewTimer(r.URL.String())
	apiDuration := metrics.NewApiDuration(r.Method)
	requestTotal := metrics.NewRequestCounter(r.URL.String(), r.Method)
	defer requestTotal.ObserveRequestTotal()
	defer apiDuration.ObserveApiDuration()
	defer timer.ObserveTotal()
	defer timer.ObserveStep("LastSub")
	// 获取参数
	user := r.URL.Query().Get("user")
	// 生成随机数
	delay := randInt(0, 2000)
	// 睡眠随机时间，模拟延时
	time.Sleep(time.Millisecond * time.Duration(delay))

	glog.V(2).Infoln("Entering route Handler...")
	printIpOk(r)
	// 调整请求头为小写
	req, err := http.NewRequest("GET", "http://httpserver1", nil)
	if err != nil {
		glog.Info("HTTP get failed with error: ", "error", err)
	}
	lowerCaseHeader := make(http.Header)
	// 设置环境变量
	//os.Setenv("VERSION","V0.1")
	// 响应头中设置环境变量值
	reson.Header().Set("version", os.Getenv("VERSION"))

	// 打印请求头
	//io.WriteString(reson, "===================Details of the http request header:============\n")
	for k, v := range r.Header {
		lowerCaseHeader[strings.ToLower(k)] = v
		reson.Header().Set(k, strings.Join(v, ""))
		//io.WriteString(reson,fmt.Sprintf("%s=%s\n",k,v))
	}
	req.Header = lowerCaseHeader
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		glog.Info("HTTP get failed with error: ", "error", err)
	} else {
		glog.Info("HTTP get succeeded")
	}
	if resp != nil {
		resp.Write(reson)
	}
	io.WriteString(reson, "comon 20s OK\n")
	if user == "" {
		user = "stranger"
	}
	io.WriteString(reson, fmt.Sprintf("hello [%s]\n", user))

}

// healthzHandler 路由配置-返回 healthz 健康监测
func healthzHandler(reson http.ResponseWriter, r *http.Request) {
	// 业务开始
	glog.V(2).Infoln("Entering healthz Handler...")
	printIpOk(r)
	io.WriteString(reson, "OK\n")
}

// goUrlHandler 路由配置-短连接重定向
// 例：访问百度 http://127.0.0.1:8080/go/baidu
func goUrlHandler(reson http.ResponseWriter, r *http.Request) {
	// 注册指标统计
	timer := metrics.NewTimer(r.URL.String())
	apiDuration := metrics.NewApiDuration(r.Method)
	requestTotal := metrics.NewRequestCounter(r.URL.String(), r.Method)
	defer requestTotal.ObserveRequestTotal()
	defer apiDuration.ObserveApiDuration()
	defer timer.ObserveTotal()
	defer timer.ObserveStep("LastSub")
	// 业务开始
	glog.V(2).Infoln("Entering goUrl Handler...")
	tmplStr := strings.Replace(r.RequestURI, "/go/", "", 1)
	ip := utils.GetClientIp(r)

	if value, exists := goUrlCache.GetCacheValue(tmplStr); exists {
		glog.Infoln(fmt.Sprintf("Client Ip is: %s, Http status is: %d\n", ip, http.StatusSeeOther))
		http.Redirect(reson, r, value, http.StatusSeeOther)
	}

	glog.Infoln(fmt.Sprintf("Client Ip is: %s, Http status is: %d\n", ip, http.StatusNotFound))
	http.NotFound(reson, r)
}

// timeOutHandler 路由配置-延迟返回
func timeOutHandler(reson http.ResponseWriter, r *http.Request) {
	// 注册指标统计
	timer := metrics.NewTimer(r.URL.String())
	apiDuration := metrics.NewApiDuration(r.Method)
	requestTotal := metrics.NewRequestCounter(r.URL.String(), r.Method)
	defer requestTotal.ObserveRequestTotal()
	defer apiDuration.ObserveApiDuration()
	defer timer.ObserveTotal()
	defer timer.ObserveStep("LastSub")
	// 业务开始
	glog.V(2).Infoln("Entering timeOut Handler...")
	time.Sleep(15 * time.Second)
	printIpOk(r)
	io.WriteString(reson, "Do something 20s OK\n")
}

// apiJsonHandler 路由配置-返回  Json 格式的请求头信息
func apiJsonHandler(reson http.ResponseWriter, r *http.Request) {
	// 注册指标统计
	timer := metrics.NewTimer(r.URL.String())
	apiDuration := metrics.NewApiDuration(r.Method)
	requestTotal := metrics.NewRequestCounter(r.URL.String(), r.Method)
	defer requestTotal.ObserveRequestTotal()
	defer apiDuration.ObserveApiDuration()
	defer timer.ObserveTotal()
	defer timer.ObserveStep("LastSub")
	// 业务开始
	glog.V(2).Infoln("Entering apiJson Handler...")
	output, err := json.MarshalIndent(&r.Header, "", "\t")
	if err != nil {
		glog.Fatalln(fmt.Sprintf("Json error: %v \n", err))
	}
	printIpOk(r)
	reson.Header().Set("Content-Type", "application/json")
	reson.Write(output)
}

func errHandler(reson http.ResponseWriter, r *http.Request) {
	http.Error(reson, "测试超时异常：Test Gateway TimeOut 504", http.StatusGatewayTimeout)
}

// printIpOk 获取客户端ip，打印 ip 与 200 返回码
func printIpOk(r *http.Request) {
	ip := utils.GetClientIp(r)
	glog.Infoln(fmt.Sprintf("Client Ip is: %s, Http status is: %d\n", ip, http.StatusOK))
}

// randInt 生成min到max的随机数
func randInt(min int, max int) int {
	// rand.Seed通过设置不同值，保证每次执行时生成的随机数不一样
	rand.Seed(time.Now().UTC().UnixNano())
	return min + rand.Intn(max-min)
}
